#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <assert.h>
/* 信号阻塞的相关探究实验 */

/* 实验一：如果我们对所有的信号都进行了自定义捕捉---我们是不是就写了一个不会被异常或者用户杀掉的进程？ */

#if 0

void CatchSig(int signum){
    std::cout << "获得了一个信号：" << signum << std::endl;
    // switch(signum){
    //     case SIGINT:
    //     break;
    //     case SIGQUIT:
    //     break;
    // }
}

int main(){

    for(int i = 1; i <= 31; i++)
        signal(i, CatchSig);

    while(true) sleep(1);

    return 0;
}


#endif


/* 
    实验二：如果我们将2号信号blck，并且不断的获取并打印当前进程的pending信号集，
    如果我们突然发送一个2号信号，我们就应该肉眼看到pending信号集中：有一个比特位0->1
 */



#if 1

static void showPending(sigset_t &pending){
    for(int i = 1; i<=31; i++){
        if(sigismember(&pending,i)) std::cout << "1";
        else std::cout << "0";
    }
    std::cout << std::endl;
}

static void CatchSig(int signum){
    std::cout << "捕捉到的信号：" << signum << std::endl;
}

int main(){
    // 恢复指定，观察现象的代码！（捕捉进行反馈）
    signal(2, CatchSig);

    // 1. 定义信号集对象：oset 表示老的【在栈区】
    sigset_t bset, obset;    
    sigset_t pending; 

    // 2. 初始化信号集
    sigpending(&bset);
    sigpending(&obset);

    // 3. 添加要进行屏蔽的信号
    sigaddset(&bset, 2);

    /* 注意：到此为止，我们都只是对自定义申请的数据（栈上）进行修改！ */

    // 4. 设置 set 到内核中对应的进程内部：默认情况：进程不会对任何信号进行 block！
    int n = sigprocmask(SIG_BLOCK, &bset, &obset);
    assert(n==0);
    (void)n;

    std::cout << "[ " << getpid() << " ] "<< "block 2 号信号成功 ..." << std::endl;

    // 5. 重复打印当前进程的 pending 信号集
    int cnt = 0;
    while(true){
        // 5.1 获取当前进程的 pending 信号集
        sigpending(&pending);
        // 5.2 显示 pending 信号集中没有被递答的信号
        showPending(pending);
        sleep(1);
        cnt++;
        if(cnt == 20){
            /*
                说明：默认情况下：恢复对于 2 号信号的block时，确实会进行递答！
                但是，由于 2 号信号的默认处理动作是：终止进程！
                因此：无法运行到此，恢复后就会结束进程！无法看见下面的输出提示！
                解决方式：捕获一下即可！
            */
            int nn = sigprocmask(SIG_SETMASK, &obset, nullptr);     // 恢复：解除阻塞
            assert(n==0);
            (void)n;
            std::cout << "解除对于 2 号信号的 block ... " << std::endl;
        }
    }

    return 0;
}


#endif